package com.fruit.service.account;

import com.fruit.pojo.Page;
import com.fruit.pojo.account.CashApply;
import com.fruit.pojo.account.CashRule;
import com.fruit.pojo.account.user.UserAccount;
import com.fruit.pojo.pay.TransactionFlow;
import com.fruit.pojo.user.UserReal;
import com.fruit.sdk.account.AccountManager;
import com.joe.utils.common.BeanUtils;
import com.joe.utils.common.DateUtil;
import com.joe.utils.common.IDCard;
import com.joe.utils.common.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author joe
 */
@Service
@Slf4j
public class AccountService extends AbstractAccountService {

    @Override
    public Account getUserAccount(long uid) {
        log.info("查询用户{}的钱包", uid);
        if (uid <= 0) {
            log.warn("用户ID不能为null");
            return null;
        }
        UserAccount userAccount = accountMapper.getUserAccount(uid, false);
        log.debug("用户{}的钱包为：{}", uid, userAccount);
        if (userAccount == null) {
            log.warn("没有找到用户{}的钱包", uid);
            return null;
        }
        Account account = BeanUtils.copy(userAccount, Account.class);
        account.setBalance(dealDouble(userAccount.getBalance()));
        return account;
    }


    @Override
    public Page<Commission> getBill(String date, long uid, int pageNo, int size, boolean isDetail) {
        log.info("用户{}查找[{}]的账单", uid, date);
        Page<Commission> page;
        if (date != null && !DATEPATTERN.matcher(date).find()) {
            page = new Page<>();
            log.warn("日期为空或者格式错误");
            page.setData(Collections.emptyList());
            page.setPageNo(pageNo);
            return page;
        }

        if (isDetail) {
            page = getDetail(date, uid, pageNo, size);
        } else {
            page = getBill(date, uid, pageNo, size);
        }

        //处理今天、昨天
        page.getData().forEach(commission -> {
            try {
                String time = commission.getCreateTime();
                if (isDetail) {
                    commission.setCreateTime((!StringUtils.isEmpty(time) && time.length() > 10) ? time.substring(0,
                            10) : null);
                    commission.setRealTime(time);
                } else {
                    if (DateUtil.isToday(time, DateUtil.BASE)) {
                        commission.setCreateTime("今天 " + time.substring(11, 16));
                    } else if (DateUtil.isToday(DateUtil.getFormatDate(DateUtil.BASE, DateUtil.add(DateUtil.DateUnit
                                    .DAY, 1,
                            time, DateUtil.BASE)), DateUtil.BASE)) {
                        commission.setCreateTime("昨天 " + time.substring(11, 16));
                    }
                }
            } catch (Exception e) {
                log.error("处理列表页时间{}时异常", commission, e);
            }
        });

        return page;
    }

    @Override
    public Commission getCommission(long id, long uid) {
        if (id <= 0 || uid <= 0) {
            log.warn("用户ID或者佣金详情ID不能小于0");
            return null;
        }
        log.info("查询ID为{}的流水详情", id);
        TransactionFlow transactionFlow = accountMapper.getTransactionFlow(id);
        log.debug("ID为{}的流水详情为：{}", id, transactionFlow);
        if (transactionFlow == null || transactionFlow.getUserId() != uid) {
            log.warn("ID为{}的佣金详情不存在或者不属于用户{}", id, uid);
            return null;
        }
        Commission commission = convert(transactionFlow, false);

        //处理除标题外的其他数据
        if (commission instanceof CashOut) {
            dealCashOut((CashOut) commission);
        } else if (commission instanceof CashBack) {
            dealCashBack((CashBack) commission);
        } else if (commission instanceof Consume) {
            dealConsume((Consume) commission, transactionFlow.getState());
        } else {
            log.error("不存在类型：{}", commission.getClass());
        }

        log.debug("用户{}的佣金详情[{}]为：{}", uid, id, commission);
        return commission;
    }

    @Override
    public UserReal isReal(long uid) {
        log.info("查询用户{}的实名认证状态", uid);
        if (uid <= 0) {
            return null;
        }
        UserReal userReal = accountMapper.getUserReal(uid);
        log.debug("用户{}的实名认证状态为：{}", uid, userReal);

        if (checkUserReal(userReal) == 4 || checkUserReal(userReal) == 2) {
            String name = userReal.getRealName();
            userReal.setRealName("**" + name.substring(name.length() - 1));
            String card = userReal.getIdNumber();
            userReal.setIdNumber(card.substring(0, 1) + "**********" + card.substring(card.length() - 1));
        }

        return userReal;
    }

    @Override
    public int applyCert(long uid, String card, String name, String code) {
        log.info("用户{}申请实名认证，身份证为：{}，真实姓名为：{}，验证码为：{}", uid, card, name, code);
        if (uid < 0 || StringUtils.isEmpty(card) || StringUtils.isEmpty(name) || StringUtils.isEmpty(code)) {
            return 3;
        }

        if (validateCode(noticeManager.getUserPhone(uid), "certApply", code) != 0) {
            log.warn("实名认证用户验证码错误");
            return 5;
        }

//        Lock lock = LockService.getLock("applyCertification/" + String.valueOf(uid));
//        加锁保证下列操作的原子性，此处需要替换为分布式锁保证分布式下的原子性
//        lock.lock();
        lock("applyCertification/" + String.valueOf(uid));
        try {
            //判断用户是否申请实名认证
            UserReal userReal = isReal(uid);
            log.debug("当前用户{}的实名认证信息是：{}", userReal);
            int state = checkUserReal(userReal);
            if (state == 2 || state == 4) {
                log.warn("用户{}已申请实名认证，实名认证状态为：{}，不能重复申请", uid, state);
                return 4;
            }

            boolean flag = false;
            if (userReal == null) {
                flag = true;
                userReal = new UserReal();
            } else {
                userReal.setCommitCount(userReal.getCommitCount() + 1);
            }

            if (userReal.getCommitCount() >= (AccountManager.MAXCERT + 1)) {
                log.warn("用户{}申请实名认证次数过多，请走人工通道", uid);
                return 2;
            }


            //构建用户实名认证信息
            userReal.setRealName(name);
            userReal.setIdNumber(card);
            userReal.setType("00");
            userReal.setRemark("自动审核");
            userReal.setUserId(uid);

//            Lock cardLock = LockManager.getLock("applyCertification/" + card);
            //加锁保证下列操作的原子性，防止高并发下插入重复的身份证导致身份证被重复使用
//            cardLock.lock();

            lock("applyCertification/" + card);
            try {
                if (checkIdCard(card)) {
                    log.warn("身份证号{}有人使用");
                    return 6;
                }
                //下列代码块必须在try块中，保证身份证不被重复使用
                boolean success = false;
                if (check(card, name)) {
                    success = true;
                    log.info("用户{}实名认证成功", uid);
                    userReal.setState(stateConvert(4));
                } else {
                    log.warn("用户{}实名认证失败，身份证号是：{}，真实姓名是：{}", uid, card, name);
                    userReal.setState(stateConvert(3));
                }

                log.debug("用户{}的实名认证信息为：{}", uid, userReal);
                if (flag) {
                    userReal.setCreateTime(DateUtil.getFormatDate(DateUtil.BASE));
                    accountMapper.saveUserReal(userReal);
                } else {
                    accountMapper.updateCert(userReal);
                }
                return success ? 0 : userReal.getCommitCount() >= AccountManager.MAXCERT ? 2 : 1;
            } finally {
                unlock("applyCertification/" + card);
            }
        } finally {
            unlock("applyCertification/" + String.valueOf(uid));
        }
    }

    @Override
    public int applyCertification(long uid, String name, String idcard, String type, String imgFront, String
            imgCon, String code) {
        log.info("用户{}申请实名认证，参数为：{}:{}:{}:{}:{}", uid, name, idcard, type, imgFront, imgCon);
        if (uid <= 0 || StringUtils.isEmpty(name) || StringUtils.isEmpty(idcard) || !IDCard.check(idcard) ||
                StringUtils.isEmpty(type) || StringUtils.isEmpty(imgCon) || StringUtils.isEmpty(imgFront)) {
            log.debug("用户参数不正确");
            return 2;
        }
//        Lock lock = LockService.getLock("applyCertification/" + String.valueOf(uid));
        //加锁保证下列操作的原子性，此处需要替换为分布式锁保证分布式下的原子性
//        lock.lock();
        lock("applyCertification/" + String.valueOf(uid));
        try {
            //判断用户是否申请实名认证
            UserReal userReal = isReal(uid);
            int state = checkUserReal(userReal);
            if (state == 2 || state == 4) {
                log.warn("用户{}已申请实名认证，实名认证状态为：{}，不能重复申请", uid, state);
                return 4;
            }

            if (validateCode(noticeManager.getUserPhone(uid), "certApplyByHuman", code) != 0) {
                log.warn("实名认证人工通道用户验证码错误");
                return 1;
            }

//            Lock cardLock = LockManager.getLock("applyCertification/" + idcard);
            //加锁保证下列操作的原子性，防止高并发下插入重复的身份证导致身份证被重复使用
//            cardLock.lock();
            lock("applyCertification/" + idcard);
            try {
                if (checkIdCard(idcard)) {
                    log.warn("身份证{}已经有人在使用了", idcard);
                    return 3;
                }

                boolean flag = false;
                if (userReal == null) {
                    flag = true;
                    userReal = new UserReal();
                } else {
                    userReal.setCommitCount(userReal.getCommitCount() + 1);
                }


                //构建用户实名认证信息
                userReal.setRealName(name);
                userReal.setIdNumber(idcard);
                userReal.setType(type);
                userReal.setCardImageFront(imgFront);
                userReal.setCardImageCon(imgCon);
                userReal.setState(stateConvert(2));
                userReal.setUserId(uid);
                userReal.setRemark(null);
                log.debug("用户{}的实名认证信息为：{}", uid, userReal);
                if (flag) {
                    userReal.setCreateTime(DateUtil.getFormatDate(DateUtil.BASE));
                    accountMapper.saveUserReal(userReal);
                } else {
                    accountMapper.updateCert(userReal);
                }
                return 0;
            } finally {
                unlock("applyCertification/" + idcard);
            }
        } finally {
            //此处需要注意如果上述操作存在事务，那么应该在锁释放前提交事务，否则锁将失效
            lock("applyCertification/" + String.valueOf(uid));
        }
    }

    @Override
    public String getPhone(long uid) {
        String phone = noticeManager.getUserPhone(uid);
        if (StringUtils.isEmpty(phone)) {
            return phone;
        } else {
            return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
        }
    }

    @Override
    public CashRuleDTO getMinCashout() {
        List<CashRule> cashRules = accountMapper.getCashRule();
        CashRuleDTO cashRuleDTO = new CashRuleDTO();
        if (cashRules.isEmpty()) {
            cashRuleDTO.setCashRatio(-0.1);
            cashRuleDTO.setMin("-0.1");
        } else {
            cashRuleDTO.setCashRatio(cashRules.get(0).getCashRatio().doubleValue());
            cashRuleDTO.setMin(dealDouble(cashRules.get(0).getMinCashPrice()));
        }
        return cashRuleDTO;
    }

    @Override
    public Map<String, Object> sendCertApply(long uid) {
        return sendSms(uid, "certApply");
    }

    @Override
    public Map<String, Object> sendCertApplyByHuman(long uid) {
        return sendSms(uid, "certApplyByHuman");
    }

    @Override
    public Map<String, Object> sendCashApplySms(long uid) {
        return sendSms(uid, "cashApply");
    }

    @Override
    public int cashApply(long uid, double price, String cash_mode, String alipay_account, String
            bank_card, String bank_name, String code) {
        log.debug("用户{}申请提现{}元到{}，阿里账号是：{}，银行卡号是：{}，银行是：{}", uid, price, cash_mode,
                alipay_account, bank_card, bank_name);
        String phone = noticeManager.getUserPhone(uid);
        log.debug("用户手机号是：{}", phone);
        if ("00".equals(cash_mode) && (StringUtils.isEmpty(bank_card) || StringUtils.isEmpty(bank_name))) {
            //银行卡
            log.warn("用户提现参数不正确-银行卡");
            return 1;
        } else if ("01".equals(cash_mode) && StringUtils.isEmpty(alipay_account)) {
            //支付宝
            log.warn("用户提现参数不正确-支付宝");
            return 1;
        } else if (!"00".equals(cash_mode) && !"01".equals(cash_mode)) {
            log.warn("用户提现参数不正确-提现模式不对");
            return 1;
        }
        if (uid <= 0 || price <= 0 || StringUtils.isEmpty(phone) || StringUtils.isEmpty(code)) {
            log.warn("用户提现参数不正确-");
            return 1;
        }

        int validate = validateCode(phone, "cashApply", code);
        if (validate == 1) {
            return 7;
        } else if (validate == 2) {
            return 5;
        }

        List<CashRule> cashRules = accountMapper.getCashRule();
        if (cashRules.isEmpty()) {
            log.warn("当前系统没有配置提现规则");
            return 2;
        }
        CashRule cashRule = cashRules.get(0);
        log.debug("当前系统的提现规则为：{}", cashRule);
        if (cashRule.getCashRatio().doubleValue() <= 0 || cashRule.getCashRatio().doubleValue() >= 1) {
            log.warn("当前系统没有正确配置提现规则");
            return 2;
        }

        if (price < cashRule.getMinCashPrice().doubleValue()) {
            log.warn("用户{}提现金额{}小于系统允许最小金额{}", uid, price, cashRule.getMinCashPrice().doubleValue());
            return 3;
        }

        if (checkUserReal(isReal(uid)) != 4) {
            log.warn("用户{}没有实名认证", uid);
            return 6;
        }

        //计算手续费
        BigDecimal poundage = calc(cashRule, new BigDecimal(price), cash_mode);

        if (new BigDecimal(price).subtract(poundage).doubleValue() <= 0) {
            log.warn("手续费大于提现金额，不给提现");
            return 4;
        }

        //生成提现金额
        CashApply cashApply = new CashApply();
        cashApply.setAlipay_account(alipay_account);
        cashApply.setBank_card(bank_card);
        cashApply.setBank_name(bank_name);
        cashApply.setCash_mode(cash_mode);
        cashApply.setCreate_time(DateUtil.getFormatDate("yyyy-MM-dd HH:mm:ss"));
        cashApply.setPoundage(poundage);
        cashApply.setPrice(new BigDecimal(price).subtract(poundage));
        cashApply.setReal_name(getRealName(uid, false));
        cashApply.setState("00");
        cashApply.setUser_id(uid);
        cashApply.setUpdate_time(cashApply.getCreate_time());
        //提交提现申请
        if (cashApply(cashApply)) {
            return 0;
        } else {
            log.warn("用户{}钱包余额不足，用户要提现{}", uid, price);
            return 4;
        }
    }

    @Override
    public int checkUserReal(UserReal userReal) {
        if (userReal == null) {
            return 1;
        }
        return stateConvert(userReal.getState());
    }

    /**
     * 计算手续费
     *
     * @param cashRule 提现规则
     * @param price    提现金额
     * @param cashMode 提现方式，00银行卡，01支付宝
     * @return 手续费
     */
    private BigDecimal calc(CashRule cashRule, BigDecimal price, String cashMode) {
        log.debug("当前提现规则为：{}，提现金额为：{}，计算手续费", cashRule, price);
        double dPrice = price.doubleValue();
        if (cashMode == "00") {
            //银行卡
            if (dPrice <= 10000) {
                log.debug("当前提现金额{}，手续费：{}，通过银行卡提现", dPrice, 5);
                return new BigDecimal(5);
            } else if (dPrice <= 100000) {
                log.debug("当前提现金额{}，手续费：{}，通过银行卡提现", dPrice, 10);
                return new BigDecimal(10);
            } else if (dPrice <= 500000) {
                log.debug("当前提现金额{}，手续费：{}，通过银行卡提现", dPrice, 15);
                return new BigDecimal(15);
            } else if (dPrice <= 1000000) {
                log.debug("当前提现金额{}，手续费：{}，通过银行卡提现", dPrice, 20);
                return new BigDecimal(20);
            } else {
                BigDecimal result = price.multiply(new BigDecimal(0.00002)).setScale(2, RoundingMode.HALF_UP);
                log.debug("当前提现金额{}，手续费：{}，通过银行卡提现", dPrice, result.doubleValue());
                return result;
            }
        } else {
            BigDecimal cashRatio = cashRule.getCashRatio();
            //精确到小数点后两位，四舍五入
            double result = cashRatio.multiply(price).setScale(2, RoundingMode.HALF_UP).doubleValue();
            if (result <= 2) {
                log.debug("提现{}手续费为2", price.doubleValue());
                return new BigDecimal(2);
            } else if (result >= 25) {
                log.debug("提现{}手续费为25", price.doubleValue());
                return new BigDecimal(25);
            }
            int base = (int) result;

            //设定只能返回0.5的倍数，不足的向上取整，例如2.3返回2.5,2.7返回3
            if (base == result || result == (base + 0.5)) {
                log.debug("提现{}手续费为{}", price.doubleValue(), result);
                return new BigDecimal(result);
            } else {
                BigDecimal poundage = result > (base + 0.5) ? new BigDecimal(base + 1) : new BigDecimal(base + 0.5);
                log.debug("提现{}手续费为{}", price.doubleValue(), poundage.doubleValue());
                return poundage;
            }
        }
    }
}
